﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Company.Core.Helpers;
using Company.Shell.Dialogs;
using Company.Shell.Enums;
using Company.Shell.Interfaces;
using Company.Shell.Models;
using Company.Shell.ViewModels;
using Company.Shell.Views;
using HandyControl.Controls;
using LiveCharts;
using LiveCharts.Defaults;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.TextFormatting;

namespace Company.Shell.Services
{
    class ProgramManager : ObservableObject, IProgramManager
    {
        private static string path = Path.Combine(Environment.CurrentDirectory, "programs");
        private static string extensionName = ".json";

        private ObservableCollection<ProgramEntity> programs = new();
        public ObservableCollection<ProgramEntity> Programs 
        { 
            get => programs; 
            set => SetProperty(ref programs,value); 
        }
        private ProgramEntity program = new();
        public ProgramEntity Program 
        { 
            get => program; 
            set => SetProperty(ref program, value);
        }
        private ChartValues<ObservablePoint> temperatures = new();
        public ChartValues<ObservablePoint> Temperatures 
        { 
            get => temperatures;
            set => SetProperty(ref temperatures, value);
        }
        private ObservablePoint temperature = new();
        public ObservablePoint Temperature 
        { 
            get => temperature; 
            set => SetProperty(ref temperature,value); 
        }
        private ChartValues<ObservablePoint> humidities = new();
        public ChartValues<ObservablePoint> Humidities 
        {
            get => humidities;
            set => SetProperty(ref humidities, value);
        }
        private ObservablePoint humidity = new();
        public ObservablePoint Humidity 
        { 
            get => humidity; 
            set => SetProperty(ref humidity,value);
        }
        private Visibility showTemperature = Visibility.Collapsed;
        public Visibility ShowTemperature 
        { 
            get => showTemperature; 
            set => SetProperty(ref showTemperature,value);
        }
        private Visibility showHumidity = Visibility.Collapsed;

        public Visibility ShowHumidity
        {
            get => showHumidity;
            set => SetProperty(ref showHumidity, value);
        }
        public ICommand? SelectProgramCommand { get; }
        public ICommand? CreateProgramCommand { get; }
        public ICommand? SaveProgramCommand { get; }
        public ICommand? DeleteTemperaturePointCommand { get; }
        public ICommand? DeleteHumidityPointCommand { get; }
        private IMouseManager MouseManager { get; }
        private IDialogService DialogService { get; }
        public Func<double, string> XFormatter { get; set; }
        public Func<double, string> YFormatter { get; set; }

        public ProgramManager(
            IDialogService dialogService, 
            IMouseManager mouseManager)
        {
            DialogService = dialogService;
            MouseManager = mouseManager;
            XFormatter = GetXFormatter();
            YFormatter = GetYFormatter();
            SelectProgramCommand = new RelayCommand(OnSelectProgramCommand);
            CreateProgramCommand = new RelayCommand(OnCreateProgramCommand);
            SaveProgramCommand = new AsyncRelayCommand(OnSaveProgramCommand);
            DeleteTemperaturePointCommand = new RelayCommand<ObservablePoint>(OnDeleteTemperaturePointCommand);
            DeleteHumidityPointCommand = new RelayCommand<ObservablePoint>(OnDeleteHumidityPointCommand);
            LoadPrograms();
        }

        private Func<double, string>? GetYFormatter()
        {
            return value =>
            {
                return value.ToString("F1");
            };
        }

        private Func<double, string>? GetXFormatter()
        {
            return value =>
            {
                int totalMinutes = (int)value;
                int hours = totalMinutes / 60;
                int minutes = totalMinutes % 60;
                return $"{hours:D2}:{minutes:D2}";
            };
        }

        private void OnDeleteHumidityPointCommand(ObservablePoint? point)
        {
            if (point == null) return;
            var result = HandyControl.Controls.MessageBox.Show($"确定删除{Math.Round(point.Y, 1)}", "温馨提示", MessageBoxButton.YesNo);
            if ((result == MessageBoxResult.Yes))
            {
                Humidities.Remove(point);
            }
        }

        private void OnDeleteTemperaturePointCommand(ObservablePoint? point)
        {
            if (point == null) return;
            var result = HandyControl.Controls.MessageBox.Show($"确定删除{Math.Round(point.Y,1)}", "温馨提示", MessageBoxButton.YesNo);
            if ((result== MessageBoxResult.Yes))
            {
                Temperatures.Remove(point);
            }
        }

        private async Task OnSaveProgramCommand()
        {
            if (string.IsNullOrEmpty(Program.Guid))
            {
                //保存新程序.弹窗由用户输出新程序名 IDialogService
                var t = await DialogService.ShowDialogAsync<ProgramNameView, ProgramNameViewModel, string>();
                if (t.Success && !string.IsNullOrEmpty(t.Result)) 
                {
                    await Save(t.Result);
                }
            }
            else
            {
                //更新当前程序
                await Save();
            }
        }

        private void OnCreateProgramCommand()
        {
            Program = new ProgramEntity();
            Temperatures = Program.Temperatures;
            Humidities = Program.Humidities;
        }

        private void OnSelectProgramCommand()
        {
            Temperatures = Program.Temperatures;
            Humidities = Program.Humidities;
            MouseManager.WorkMode = Enums.MouseWorkMode.默认操作;
            ShowTemperature = Visibility.Visible;
            ShowHumidity = Visibility.Visible;
        }

        public async Task Save(string filename = "")
        {
            await Task.Run(() =>
            {
                if (string.IsNullOrEmpty(Program.Guid))
                {
                    //保存新程序
                    Program.Guid = Guid.NewGuid().ToString();
                    Program.Name = filename;
                    Program.Temperatures = Temperatures;
                    Program.Humidities= Humidities;
                    Directory.CreateDirectory(path);
                    string fullname = $@"{path}\{filename}{extensionName}";
                    JsonHelper.Save(Program, fullname);
                    Add(program);
                }
                else
                {
                    //更新程序
                    Program.Temperatures = Temperatures;
                    Program.Humidities = Humidities;
                    Directory.CreateDirectory(path);
                    string fullname = $@"{path}\{Program.Name}{extensionName}";
                    JsonHelper.Save(Program, fullname);
                }
            });
            Dialog.Show<MessageDialog>();
        }

        private void Add(ProgramEntity program)
        {
            App.Current.Dispatcher.Invoke(()=>Programs.Add(program));   
        }

        private void LoadPrograms()
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(path);
            if (directoryInfo.Exists)
            {
                var files = directoryInfo.GetFiles().Where(t => t.Extension.ToLower() == extensionName.ToLower());
                foreach (var file in files)
                {
                    var program = JsonHelper.Load<ProgramEntity>(file.FullName);
                    Programs.Add(program);
                }
            }
        }

        public void Add(ObservablePoint point, MouseWorkMode mode)
        {
            switch (mode)
            {
                case MouseWorkMode.默认操作:
                    break;
                case MouseWorkMode.编制温度:
                    if (Temperatures.Count == 0)
                    {
                        point.X = 0;
                        Temperatures.Add(point);
                    }
                    else
                    {
                        int index = 0;
                        foreach (var item in Temperatures)
                        {
                            if (point.X < item.X)
                            {
                                break;                                
                            }
                            index++;
                        }
                        Temperatures.Insert(index, point);
                    }
                        break;
                case MouseWorkMode.编制湿度:
                    if (Humidities.Count == 0)
                    {
                        point.X = 0;
                        Humidities.Add(point);
                    }
                    else
                    {
                        int index = 0;
                        foreach (var item in Humidities)
                        {
                            if (point.X < item.X)
                            {
                                break;
                            }
                            index++;
                        }
                        Humidities.Insert(index, point);
                    }
                    break;
                default:
                    break;
            }
        }
    }
}
